<template>
  <div v-if="currentComponent">
    <component
      allow-clear
      style="width: 100%"
      v-bind="{
        ...currentComponent,
        ...data,
        ...props[currentComponent.config],
        onChange: (value, option) =>
          data?.type === 'upload'
            ? onChangeUpload(value)
            : onChangeValue(value, option, props[currentComponent.config]),
      }"
      v-model:value="formParam[data.key]"
      :is="currentComponent?.component"
      :key="data.key"
      :placeholder="
        data.p ||
        data.placeholder ||
        currentComponent.p ||
        `${rulesMessage[data.type]}${data.title}`
      "
      :options="findConfig(data.option, optionConfig)"
      :filter-option="
        (input, option) =>
          filterOption(
            input,
            option,
            data?.fieldNames?.label || fieldNames?.label
          )
      "
      :tree-data="findConfig(data.option, optionConfig)"
      :tree-node-filter-prop="data?.fieldNames?.label || fieldNames?.label"
      :custom-request="customRequest"
      :accept="findConfig(data.accept, formConfig)"
      :disabled="isDisabled(data.record)"
    >
      <a-button
        v-if="data.type === 'upload'"
        type="link"
        :loading="uploadLoading"
        :disabled="isDisabled(data.record)"
      >
        <!-- {{ record[data.dataIndex] || '上传' }} -->
        {{ data.text || "上传" }}
      </a-button>
    </component>
  </div>
</template>

<script setup>
import { ref, computed } from "vue";
import {
  config,
  propsConfig,
  findConfig,
  fieldNames,
  filterOption,
  rulesMessage,
} from "./index";

const emit = defineEmits(["changeValue"]);
const props = defineProps({
  data: { type: Object, required: true, default: () => ({}) },
  ...propsConfig,
});

// 避免模板中频繁的 v-if 判断，使用 computed 计算属性
const currentComponent = computed(() => {
  return config.find((item) => item.type === props.data.type);
});

// 通用禁用状态判断逻辑，使用 “===” 会导致数字和字符串不相等
// record：表格当前行数据，data：当前组件数据，form表单不包含record
const isDisabled = (record = null) => {
  const { data, disabledConfig } = props;
  const target = record || data;
  if (typeof data.disabled === "function") {
    return data.disabled({ record: target });
  }
  if (typeof data.disabled === "string") {
    // disabledKeys和disabled都存在时，进行对比相同则禁用
    if (target[data.disabledKeys] && disabledConfig[data.disabled]) {
      return !(target[data.disabledKeys] == disabledConfig[data.disabled]);
    }
    // 优先从 disabledConfig 获取外部控制状态
    if (disabledConfig && disabledConfig.hasOwnProperty(data.disabled)) {
      if (typeof disabledConfig[data.disabled] === "boolean") {
        return disabledConfig[data.disabled];
      }
      // 为字符串返回false，防止报错只接受布尔值
      return false;
    }
    // 字段级联动禁用规则：通过 record 的 key 匹配值是否相等并取反
    // 不相等则禁用，相等则打开，根据需求自行调整
    return !(target[data.disabledKeys] == target[data.disabled]);
  }
  // 直接返回静态禁用状态（Boolean）
  return !!data.disabled;
};

// 树级选择器：获取选中的完整数据项（id, name 等）
const getSelectedOption = (selectData) => {
  const { data, optionConfig } = props;
  const { value, children } = data?.fieldNames || fieldNames;
  const options = findConfig(data.option, optionConfig);
  if (!options) return null;
  // 根据选中的 value 获取对应的完整数据项（id, name 等）
  const findOption = (options, val) => {
    for (let option of options) {
      if (option[value] === val) {
        return option;
      }
      if (option[children]) {
        const result = findOption(option[children], val);
        if (result) return result;
      }
    }
    return null;
  };
  return findOption(options, selectData);
};

// 输入框/选择器事件
const onChangeValue = (e, option = {}, configs = {}) => {
  const { data, formParam } = props;
  // 简单的处理
  if (data?.change) {
    return data.change(formParam, { value: e, option });
  }
  // 如果 args 对象 存在，根据 key:'value' 进行赋值操作
  const args = data?.param || data?.params;
  // 日期类型，返回数组，需要单独处理
  const dateType = ["range", "range-time"];
  const options = getSelectedOption(e);
  if (args) {
    if (dateType.includes(data.type)) {
      for (const [index, item] of args.entries()) {
        formParam[item] = e?.[index];
      }
      return;
    }
    for (const key in args) {
      formParam[key] = options?.[args[key]];
    }
    return; // 可选
  }
  // 返回默认参数
  const { onChange } = configs;
  const eValue =
    data.type == "input" || data.type == "textarea" ? e.target.value : e;
  const eOption = data.type == "tree" ? options : option;
  const datas = { ...data, value: eValue, option: eOption };
  const currentValue = configs[datas.key];
  /**
   * onChange：不根据字段，全部返回
   * currentValue：根据字段返回，只做当前处理
   */
  const events = currentValue || onChange;
  if (events) {
    return events(datas);
  }
  // 传递给父组件
  emit("changeValue", datas);
};

// 上传附件
const fileObj = ref({});
const onChangeUpload = ({ file = {} }) => {
  const { data } = props;
  fileObj.value = data;
};

// 上传附件转Url
const uploadLoading = ref(false);
const customRequest = ({ file }) => {
  const { formParam, uploadConfig = {} } = props;
  const fileData = new FormData();
  fileData.append("file", file);
  uploadLoading.value = true;
  // 传递文件流，后端处理返回数据接口
  annexUpload(fileData)
    .then((res) => {
      const { param, params, auto, dataIndex } = fileObj.value;
      // 如果 params对象 存在，根据 key:'value' 进行赋值操作
      const args = param || params;
      // auto为true 直接全部赋值
      if (auto) {
        // for (const key in res) {
        // 	formParam[key] = res[key]
        // }
        Object.assign(formParam, res);
      }
      if (args) {
        for (const key in args) {
          formParam[key] = res[args[key]];
        }
        return; // 可选
      }
      // 返回默认参数
      const { onChange } = uploadConfig;
      const data = { ...fileObj.value, res };
      // 根据字段返回，只做当前处理
      if (uploadConfig[dataIndex]) {
        return uploadConfig[dataIndex](data);
      }
      // 有自定义事件则执行自定义事件
      if (onChange) {
        return onChange(data);
      }
      // 传递给父组件
      emit("changeValue", data);
    })
    .finally(() => {
      uploadLoading.value = false;
    });
};
</script>

<style lang="scss" scoped></style>